package com.cy.deepseeksport;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import com.cy.deepseeksport.NLP.MatchInfo;
import com.cy.deepseeksport.NLP.QuestionType;
import com.cy.deepseeksport.aiService.BochaApi;
import com.cy.deepseeksport.aiService.SportsQueryAnalyzer;
import com.cy.deepseeksport.service.search.BochaApiClient;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.service.AiServices;
import io.github.pigmesh.ai.deepseek.core.DeepSeekClient;
import io.github.pigmesh.ai.deepseek.core.chat.ChatCompletionModel;
import io.github.pigmesh.ai.deepseek.core.chat.ChatCompletionRequest;
import io.github.pigmesh.ai.deepseek.core.chat.ChatCompletionResponse;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static com.cy.deepseeksport.NLP.TeamNameSearch.indexName;

@Slf4j
@CrossOrigin("*")
@RestController
public class ChatController {

    @Autowired
    @Qualifier("deepSeekr1Client")
    private DeepSeekClient deepSeekClient;

    @Resource
    private BochaApi bochaApi;

    @GetMapping(value = "/chat")
    public Flux<ChatCompletionResponse> tangent(String prompt) throws IOException {

        OpenAiChatModel littleModel = OpenAiChatModel.builder().apiKey("26f9ab1f-3509-4f8e-b06e-7495bc93373a").baseUrl("https://ark.cn-beijing.volces.com/api/v3").maxTokens(100).modelName("doubao-1.5-vision-lite-250315").build();


        SportsQueryAnalyzer simpleAgent = AiServices.create(SportsQueryAnalyzer.class, littleModel);

        QuestionType questionType = simpleAgent.classifyUserQuestion(prompt);

        switch (questionType) {
            case SIMPLE_CHAT:


                return deepSeekClient.chatFluxCompletion(ChatCompletionRequest.builder().model(ChatCompletionModel.DEEPSEEK_CHAT).addUserMessage(prompt).maxTokens(1000).build());

            case PREDICT_MATCH:
                // 比赛预测类对话
                SportsQueryAnalyzer matchInfoAnalyzer = AiServices.create(SportsQueryAnalyzer.class, OpenAiChatModel.builder().apiKey("26f9ab1f-3509-4f8e-b06e-7495bc93373a").baseUrl("https://ark.cn-beijing.volces.com/api/v3/bots").maxTokens(100).modelName("bot-20250525124406-cqcw7").build());

                //parseMatchData(matchInfoAnalyzer, prompt);


                //String[] teamKeywords = null;
                return doMatchPredict(prompt, simpleAgent);

            case REJECT:

                return deepSeekClient.chatFluxCompletion(ChatCompletionRequest.builder().model(ChatCompletionModel.DEEPSEEK_CHAT).addUserMessage("你是体育领域的智能回答助手，擅长基于数据分析预测比赛，但是用户提问了非体育相关的问题，请委婉拒绝。用户问题是：" + prompt).maxTokens(1000).build());

            default:
                // 默认就是联网搜索

                return doWebSearch(prompt, simpleAgent);

        }

    }

    @Resource
    private ElasticsearchClient esClient;

    private void parseMatchData(SportsQueryAnalyzer analyzer, String prompt) throws IOException {
        MatchInfo matchInfo = analyzer.extractTeamInfo(prompt);


        String[] teamKeywords = matchInfo.getTeamNames();

        if (!Objects.isNull(matchInfo.getMatchDate())) {

            SearchResponse<Map> response = esClient.search(s -> s.index(indexName).query(q -> q.bool(b -> {
                //球队名称模糊检索
                b.must(m -> m.bool(bb -> {
                    for (String keyword : teamKeywords) {
                        String phrase;
                        if (keyword.endsWith("队")) {
                            phrase = keyword.substring(0, keyword.length() - 1).trim();
                        } else {
                            phrase = keyword;
                        }
                        bb.should(sh -> sh.matchPhrase(mp -> mp.field("info").query(phrase)));

                    }
                    return bb;
                }));

                return b;
            })).size(1), Map.class);

            // 3. 处理结果
            List<Hit<Map>> hits = response.hits().hits();

            if (hits.isEmpty()) {
                log.info("没有找到比赛");

            }
            log.info("查询结果：{}", hits.get(0).source().get("info"));
            log.info("比赛id：{}", hits.get(0).source().get("id"));
            log.info("比赛时间：{}", hits.get(0).source().get("match_time"));
            log.info("数据可信度：{}", hits.get(0).score());


        }
    }


    // 对具体比赛 进行分析预测
    private Flux<ChatCompletionResponse> doMatchPredict(String prompt, SportsQueryAnalyzer simpleAgent) {
        return doWebSearchWithMatch(prompt, simpleAgent);
    }

    private Flux<ChatCompletionResponse> doWebSearchWithMatch(String prompt, SportsQueryAnalyzer simpleAgent) {

        String searchExactlyKeyWord = simpleAgent.extractSearchExactlyKeyWord(prompt);

        String websearchContent = bochaClient.search(searchExactlyKeyWord.replace("预测", "").replace("分析", ""), "noLimit", 50, false, false);

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
        LocalDate today = LocalDate.now();
        String formattedDate = today.format(formatter);
        String format = String.format("# 以下内容是基于用户发送的消息的搜索结果:\n%s\n# 你是专业的足球比赛预测专家，请基于数据和新闻资讯对该场比赛进行深入分析。在分析比赛数据前要先确认比赛的日期和场地，分析后要给出最有可能的唯一预测结果。在回答时，请注意以下几点：\n" +
                        "        - 今天是%s。\n" +
                        "        - 并非搜索结果的所有内容都与用户的问题密切相关，你需要结合问题，对搜索结果进行甄别、筛选。\n" +
                        //"        - 优先提供信息完整、最相关的列举项；如非必要，不要主动告诉用户搜索结果未提供的内容。\n" +
                        //"        - 如果回答很长，请尽量结构化、分段落总结。如果需要分点作答，尽量控制在5个点以内，并合并相关的内容。\n" +
                        //"        - 对于客观类的问答，如果问题的答案非常简短，可以适当补充一到两句相关信息，以丰富内容。\n" +
                        //"        - 你需要根据用户要求和回答内容选择合适、美观的回答格式，确保可读性强。\n" +
                        //"        - 你的回答应该综合多个相关网页来回答，不能重复引用一个网页，但是不要再回答中提到引用页面。\n" +
                        "# 用户消息为： %s",
                websearchContent,
                formattedDate,
                prompt);

        //return deepSeekClient.chatFluxCompletion();
        return deepSeekClient.chatFluxCompletion(format);
    }


    @Autowired
    private BochaApiClient bochaClient;


    // 对话助手的默认功能，对用户查询内容进行联网搜索
    private Flux<ChatCompletionResponse> doWebSearch(String prompt, SportsQueryAnalyzer simpleAgent) {
        String searchExactlyKeyWord = simpleAgent.extractSearchExactlyKeyWord(prompt);
        //SearchRequest searchRequest = SearchRequest.builder()
        //        .enable(true)
        //        .query(searchExactlyKeyWord)
        //        .freshness(FreshnessEnums.NO_LIMIT)
        //        .summary(true)
        //        .count(50)
        //        .page(1)
        //        .build();
        //
        //return deepSeekClient.chatSearchCompletion(prompt, searchRequest);
        String websearchContent = bochaClient.search(searchExactlyKeyWord.replace("预测", "").replace("分析", ""), "noLimit", 50, false, false);

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
        LocalDate today = LocalDate.now();
        String formattedDate = today.format(formatter);
        String format = String.format("# 以下内容是基于用户发送的消息的搜索结果:\n%s\n在回答时，请注意以下几点：\n" +
                        "        - 今天是%s。\n" +
                        "        - 并非搜索结果的所有内容都与用户的问题密切相关，你需要结合问题，对搜索结果进行甄别、筛选。\n" +
                        "        - 优先提供信息完整、最相关的列举项；如非必要，不要主动告诉用户搜索结果未提供的内容。\n" +
                        "        - 如果回答很长，请尽量结构化、分段落总结。如果需要分点作答，尽量控制在5个点以内，并合并相关的内容。\n" +
                        "        - 对于客观类的问答，如果问题的答案非常简短，可以适当补充一到两句相关信息，以丰富内容。\n" +
                        "        - 你需要根据用户要求和回答内容选择合适、美观的回答格式，确保可读性强。\n" +
                        "        - 你的回答应该综合多个相关网页来回答，不能重复引用一个网页，但是不要再回答中提到引用页面。\n" +
                        "# 用户消息为： %s",
                websearchContent,
                formattedDate,
                prompt);

        //return deepSeekClient.chatFluxCompletion();
        return deepSeekClient.chatFluxCompletion(format);
    }
}
